#pragma once
#include <iostream>
#include <memory>
#include <unordered_map>
#include <sys/epoll.h>
#include "socket.hpp"
#include "connection.hpp"
#include "epoll_object.hpp"

#define BLOCK_EPOLL -1

// 反应堆类，我们可以直接将这个TcpServer类 名字改为 Reactor类
class TcpServer
{
    static const int max_events = 64;
    bool IsConnectionExist(int sock_fd)
    {
        auto pos = _connections.find(sock_fd);
        if (pos == _connections.end())
            return false;
        else
            return true;
    }

    // 实现多线程！！！
    // 1.将事件派发进行多线程！！！

    void LoopOnce() // 进行事件派发
    {
        
        int n = _epoller.WaitEpoller(_read_events, max_events, _timeout);
        for (size_t i = 0; i < n; i++)
        {
            int fd = _read_events[i].data.fd;
            uint32_t events = _read_events[i].events;

            // 将fd检测的问题（异常情况），全部转换为读写问题
            if (events & EPOLLERR)
            {
                events |= (EPOLLIN | EPOLLOUT);
            }
            if (events & EPOLLHUP)
            {
                events |= (EPOLLIN | EPOLLOUT);
            }

            // 所有的IO操作都转化为读写
            // 而IO的实现在connection的回调方法内！！！
            
            // 这里的conn分为两种 
            // 1.listensock的等待文件套接字
            // 2.文件套接字进行IO
            if ((events & EPOLLIN) && IsConnectionExist(fd)) // 读事件就绪
            {
                _connections[fd]->_recv_func(_connections[fd]);
            }
            if ((events & EPOLLOUT) && IsConnectionExist(fd)) // 写事件就绪
            {
                _connections[fd]->_send_func(_connections[fd]);
            }
        }
    }

public:
    TcpServer(int port) : _port(port), _isrunning(false), _timeout(BLOCK_EPOLL)
    {
        _epoller.InitEpoller();
    }
    ~TcpServer() {}

    void AddConnection(Connection *conn)
    {
        if (conn == nullptr)
            return;
        // 表示当这个对应fd不存在哈希表中，就添加
        if (IsConnectionExist(conn->GetSockFd()) == false)
        {
            // 添加链接
            _connections.insert(std::make_pair(conn->GetSockFd(), conn)); // _connections[conn->GetSockFd()] = conn;

            lg.LogMessage(Info, "add a new Connection success, fd = %d\n", conn->GetSockFd());
            // 让epoller管理，本质上就是关心这些事件
            _epoller.AddEvent(conn->GetSockFd(), conn->GetEvents());
        }
    }
    void Dispatcher()   // 实现不断地进行事件派发
    {
        _isrunning = true;
        while (1)
        {
            LoopOnce();
        }
        _isrunning = false;
    }
    void EnableIO(int sock_fd, int read_enable, int write_enable) // 实现用户设置IO读写
    {
        // 文件描述符不合法
        if (IsConnectionExist(sock_fd) == false)
        {
            return;
        }

        uint32_t events = ((read_enable ? EPOLLIN : 0) | (write_enable ? EPOLLOUT : 0) | EPOLLET);
        // 1.修改关心的事件，并将新的事件给Connection一份
        _connections[sock_fd]->SetEvents(events);
        // 2.epoller设置进内核
        _epoller.ModEvent(sock_fd, events);
    }
    void CloseConnection(int sock_fd)
    {
        if(IsConnectionExist(sock_fd) == false)
        {
            return;
        }
        // 1.除去epoll关心
        _epoller.DelEvent(sock_fd);
        // 2.除去哈希表中的映射
        _connections[sock_fd]->SetEvents(0);
        _connections.erase(sock_fd);
        // 3.关闭文件描述符
        close(sock_fd);
    }

private:
    int _port;
    bool _isrunning;
    std::unordered_map<int, Connection *> _connections;
    Epoll::Epoller _epoller;
    struct epoll_event _read_events[max_events];    // 
    int _timeout;
};